import os
import time
from subprocess import Popen, PIPE, CalledProcessError
from datetime import datetime

from lib.dict4ini import DictIni


def get_line_from_file(fp):
    with open(fp) as fb:
        for line in fb:
            yield line

def str2datetime(strs, fmt='%b %d %H:%M:%S'):
    '''
    >>> dt = str2datetime('Sep 22 02:38:21')
    >>> type(dt)
    <type 'time.struct_time'>
    >>> dt.tm_mon
    9
    >>> dt.tm_mon
    9
    >>> dt.tm_min
    38
    '''
    return time.strptime(strs, fmt)

def convert_dict_value_to_int(d):
    '''
    >>> d = convert_dict_value_to_int({'a': 'str_a', 'b': '1'})
    >>> type(d['a'])
    <type 'str'>
    >>> type(d['b'])
    <type 'int'>
    '''
    for k, v in d.items():
        if v.isdigit():
            d[k] = int(v)
    return d

def raw2lines(raw, headers=0):
    '''convert raw output to lines'''
    lines = [l for l in raw.split('\n') if l.strip()]
    if headers >= 1:
        lines = lines[headers:]
    return lines


def get_datetime(fmt='%Y-%m-%d %H:%M:%S'):
    return datetime().strftime(fmt)

def level_triggered(value, thresholds):
    '''
    >>> thresholds = [10, 30]
    >>> level_triggered(9, thresholds)
    'info'
    >>> level_triggered(10, thresholds)
    'warn'
    >>> level_triggered(20, thresholds)
    'warn'
    >>> level_triggered(30, thresholds)
    'error'
    >>> level_triggered(45, thresholds)
    'error'
    '''
    md = {0: 'error',
          1: 'warn',
          2: 'info',
          3: 'debug'}

    value = int(value)
    index = 0
    length = len(thresholds)
    thresholds.sort()

    _flag = False
    for index, v in enumerate(thresholds[::-1]):
        if value >= v:
            _flag = True
            break

    if not _flag:
        index = length
    return md[index]

def check_type(obj, *types):
    if not isinstance(obj, types):
        raise TypeError('"%s" must be %s' % (repr(obj), repr(types)))
    return obj

def get_module_name(fn):
    '''
    >>> get_module_name('/a.py')
    'a'
    >>> get_module_name('abc.pyc')
    'abc'
    >>> get_module_name('/a/b/c.pyo')
    'c'
    '''
    head, tail = os.path.split(fn)
    mn, ext = os.path.splitext(tail)
    if ext not in ['.py', '.pyc', '.pyo']:
        raise TypeError('%s is not a regular python module' % fn)

    return mn

def get_work_dir():
    path = os.path.abspath(os.path.dirname(__file__))
    return path

def is_path_relative(path):
    if path.startswith('/'):
        return False
    return True

def is_path_existed(path):
    if is_path_relative(path):
        path = os.path.join(get_work_dir(), path)
    return os.path.exists(path)

def mkdir(path):
    if is_path_existed(path):
        os.mkdirs(path)

def ini2dict(ini):
    return DictIni(ini, format="%s=%s")

class CallProcess(object):
    def __init__(self, cmd, cmd_bufsize=4096):
        self.cmd = check_type(cmd, str)
        self.cmd_bufsize = cmd_bufsize

    def __call__(self, check_call=False):
        process = Popen(self.cmd,
                        shell=True,
                        stdout=PIPE,
                        stderr=PIPE,
                        bufsize=self.cmd_bufsize)

        # block until finish
        self.retcode = process.wait()
        self.stdout = process.stdout.read().strip()
        self.stderr = process.stderr.read().strip()
        if check_call:
            if self.retcode != 0:
                raise CalledProcessError(self.retcode, self.cmd, self.stderr)

def test():
    import doctest
    doctest.testmod()

if __name__ == "__main__":
    test()
